package com.ku.kill.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import com.ku.kill.dao.PromoDOMapper;
import com.ku.kill.dataobject.PromoDO;
import com.ku.kill.error.BusinessException;
import com.ku.kill.error.EmBusinessError;
import com.ku.kill.service.ItemService;
import com.ku.kill.service.PromoService;
import com.ku.kill.service.UserService;
import com.ku.kill.service.model.ItemModel;
import com.ku.kill.service.model.PromoModel;
import com.ku.kill.service.model.UserModel;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @program: kill2
 * @description:
 * @author: JokerKu
 * @create: 2020-04-03 16:38
 **/

@Service
public class PromoServiceImpl implements PromoService {
    @Autowired
    private PromoDOMapper promoDOMapper;
    @Autowired
    private ItemService itemService;
    @Autowired
    private UserService userService;
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public PromoModel getPromoByItemId(Integer itemId) {
        //获取商品的秒杀活动信息
        PromoDO promoDO = promoDOMapper.selectPromoByItemId(itemId);
        //DO-->Model

        PromoModel promoModel = covertModelFromDO(promoDO);
        //判断活动的开始时间
        if (promoModel != null) {
            LocalDateTime now = LocalDateTime.now();
            //现在的时间在开始时间之前--未开始
            if (now.isBefore(promoModel.getStartDate())) {
                promoModel.setStatus(1);
                //现在的时间在结束时间后--已结束
            } else if (now.isAfter(promoModel.getEndDate())) {
                promoModel.setStatus(3);
            } else {
                //其他就是正在进行中
                promoModel.setStatus(2);
            }
        }
        return promoModel;
    }

    @Override
    public void publishPromo(Integer promoId) throws BusinessException {
        PromoDO promoDO = promoDOMapper.selectByPrimaryKey(promoId);
        if (promoDO.getId() == null) {
            return;
        }
        ItemModel item = itemService.getItemById(promoDO.getItemId());
        //将库存同步到Redis内
        redisTemplate.opsForValue().set("promo_item_stock" + item.getId(), item.getStock().toString());

        //发布库存的同时 生成一个秒杀大闸 限制令牌发放的数量   发放5倍库存数量的令牌
        redisTemplate.opsForValue().set("promo_door_count_" + promoDO.getId(), String.valueOf(5 * item.getStock()));
    }

    @Override
    public String generateSecondKillToken(Integer promoId, Integer itemId, Integer userId) throws BusinessException {

        Boolean hasKey = redisTemplate.hasKey("promo_item_stock_invalid_" + itemId);
        //存在这个key 表明该商品已经售罄
        if (hasKey != null && hasKey) {
            throw new BusinessException(EmBusinessError.STOCK_NOT_ENOUGH);
        }

        //1.查询商品是否存在
        ItemModel itemModel = itemService.getItemWithCacheById(itemId);
        if (itemModel == null) {
            return null;
        }
        //2.查询用户是否存在
        UserModel userModel = userService.getUserByIdInCache(userId);
        if (userModel == null) {
            return null;
        }
        //3.获取商品的秒杀活动信息
        PromoDO promoDO = promoDOMapper.selectByPrimaryKey(promoId);
        //DO-->Model
        PromoModel promoModel = covertModelFromDO(promoDO);

        if (promoModel != null) {
            //判断活动的开始时间
            LocalDateTime now = LocalDateTime.now();
            //现在的时间在开始时间之前--未开始
            if (now.isBefore(promoModel.getStartDate())) {
                promoModel.setStatus(1);
                //现在的时间在结束时间后--已结束
            } else if (now.isAfter(promoModel.getEndDate())) {
                promoModel.setStatus(3);
            } else {
                //其他就是正在进行中
                promoModel.setStatus(2);
            }

            //获取秒杀大闸的count数量
            Long leftCount = redisTemplate.opsForValue().increment("promo_door_count_" + promoDO.getId(), -1);
            //对秒杀大闸中的令牌-1后的数量任>=0的话，那么可以生成一个令牌
            if (leftCount != null && leftCount >= 0) {
                //生成秒杀令牌token 保存到redis中 5分钟有效
                if (promoModel.getStatus() == 2) {
                    String killToken = IdUtil.fastSimpleUUID();
                    redisTemplate.opsForValue().set("promo_token_" + promoId + "_itemId_" + itemId + "_userId_" + userId, killToken, 5, TimeUnit.MINUTES);//5分钟过期时间
                    return killToken;
                }
            }


        }
        return null;
    }

    private PromoModel covertModelFromDO(PromoDO promoDO) {
        if (promoDO == null) {
            return null;
        }
        PromoModel promoModel = new PromoModel();
        BeanUtil.copyProperties(promoDO, promoModel);

        return promoModel;
    }
}
